﻿using Dapper;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;

namespace HY.DataCore
{
    /// <summary>
    /// 数据Dapper工具(除了暴露Dapper的常用方法之外，还封装了事务相关的方法。这个类可以比较简单，也可以复杂到支持泛型Insert、Update、Delete等操作。如果需要暴露更多的Dapper方法，可以在这里添加。)
    /// </summary>
    public class DapperContext : IDisposable
    {
        /// <summary>
        /// 数据连接
        /// </summary>
        public IDbConnection dbConnecttion { get; private set; }

        /// <summary>
        /// 数据事务
        /// </summary>
        public IDbTransaction dbTransaction { get; set; }

        /// <summary>
        /// 持久化行数
        /// </summary>
        public int PersistenceLine = 0;

        /// <summary>
        /// 尝试打开数据库连接
        /// </summary>
        public void TryOpenConnection()
        {
            if (this.dbConnecttion.State == ConnectionState.Closed)
            {
                try { this.dbConnecttion.Open(); }
                catch (Exception e)
                {
                    throw e;
                }
            }
        }

        #region 构造函数

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="connString">连接字符串</param>
        /// <param name="providerName">提供商名称</param>
        public DapperContext(string connString, string providerName)
        {
            DbProviderFactory dbfactory = DbProviderFactories.GetFactory(providerName);
            this.dbConnecttion = dbfactory.CreateConnection();
            if (dbConnecttion != null) this.dbConnecttion.ConnectionString = connString;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public DapperContext() : this("ConnString")
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="connectionStringName">连接字符串名称</param>
        public DapperContext(string connectionStringName):this(ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString, ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName)
        {
        }

        /// <summary>
        /// 构造函数，用于EF和Dapper共用一个连接对象
        /// </summary>
        /// <param name="dbConnecttion">数据库连接对象</param>
        public DapperContext(DbConnection dbConnecttion)
        {
            this.dbConnecttion = dbConnecttion;
        }
        #endregion

        #region 事务相关
        /// <summary>
        /// 开始事务
        /// </summary>
        public void BeginTransaction()
        {
            this.TryOpenConnection();
            this.BeginTransaction(this.dbConnecttion.BeginTransaction());
        }

        /// <summary>
        /// 设置事务
        /// </summary>
        /// <param name="dbTransaction">事务对象</param>
        public void BeginTransaction(IDbTransaction dbTransaction)
        {
            this.TryOpenConnection();
            this.dbTransaction = dbTransaction;
            this.PersistenceLine = 0;
        }

        /// <summary>
        /// 提交事务
        /// </summary>
        public int Commit()
        {
            if (this.dbTransaction != null)
            {
                this.dbTransaction.Commit();
                this.dbTransaction = null;//Commit之后虽会将事务对象的连接信息清空，但对象本身仍旧存在。为方便外部获取事务对象后判定空，此处清空事务对象。
            }
            int result = this.PersistenceLine;
            this.PersistenceLine = 0;
            return result;
        }

        /// <summary>
        /// 回滚事务
        /// </summary>
        public void Rollback()
        {
            if (this.dbTransaction != null)
            {
                this.dbTransaction.Rollback();
                this.dbTransaction = null;//Rollback之后虽会将事务对象的连接信息清空，但对象本身仍旧存在。为方便外部获取事务对象后判定空，此处清空事务对象。
                this.PersistenceLine = 0;
            }
        }

        /// <summary>
        /// 获取事务对象
        /// </summary>
        /// <returns></returns>
        public DbTransaction GetTransaction()
        {
            return this.dbTransaction as DbTransaction;
        }
        #endregion
        
        #region 释放资源
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (dbTransaction != null) { try { dbTransaction.Dispose(); dbTransaction = null; } catch { } }
                if (dbConnecttion != null) { try { dbConnecttion.Dispose(); dbConnecttion = null; } catch { } }
            }
        }

        ~DapperContext() { Dispose(false); }
        #endregion
    }
}
